#include <stdio.h>
#include <stdlib.h>

#include "ListWrap.h"

typedef struct Elephant
{
    int age;
    int weight;
    char name[200];
}Elephant;

/**     struct Person & Match func    **/
typedef struct Person_t
{
    int age;
    int id;
    char name[200];
}Person;

int IsPersonMatch(Person* _data, void* _param)
{
 return (_data)->age == *((int*)_param);
}
/***************************************/


/*typedef List ElephantList;

Elephant* ElephantListHead(ElephantList* _list);*/

GENERATE_LIST_HEADER(Elephant)

GENERATE_LIST_IMP(Elephant)

GENERATE_LIST_HEADER(Person)

GENERATE_LIST_IMP(Person)

/***************************************************************************************************************/
/*********************************************    LIST_UTEST    *************************************************/
/***************************************************************************************************************/
#define IS_SUCCESS(X) !X?"SUCCESS":"FAILURE"   /*  Macro to print on regression tests       */
#define IF_FAIL(X) if(X){printf("FAIL IN %s TEST, IN LINE %d\n",#X,__LINE__); return 1;}
/*******************    Forward Declerations    ******************/
int ListRegression_Utest();
int ListPush_Utest();
int ListPop_Utest();
int ListFindIf_Utest();
int ListMultipile_Utest();
/*****************************************************************/

/****   IsMatch function for test   ****/
int IsIntMatch(void* _data, void* _param)
{
 return *((int*)_data) == *((int*)_param);
}
/***************************************/

int ListRegression_Utest()
{
    printf("ListPush_Utest: %s\n\n", IS_SUCCESS(ListPush_Utest()));
    printf("ListFindIf_Utest: %s\n\n", IS_SUCCESS(ListFindIf_Utest()));
    printf("ListPop_Utest: %s\n\n", IS_SUCCESS(ListPop_Utest()));
    printf("ListMultipile_Utest: %s\n", IS_SUCCESS(ListMultipile_Utest()));

    return 0;
}


int ListPush_Utest()
{
    PersonList*   list = PersonListNew()            ;
    Person     pArr[5];
    Person     pArr2[2]       ;
    Person*    data1                       ;
    Person*    data2                       ;
    int     i                           ;
    int     numOfE                      ;

    for(i = 0; i < sizeof(pArr)/sizeof(Person); ++i)
    {
        (pArr + i)->age = i;
        (pArr + i)->id = i*i;
    }

    for(i = 0; i < sizeof(pArr2)/sizeof(Person); ++i)
    {
        (pArr2 + i)->age = i + sizeof(pArr)/sizeof(Person);
        (pArr2 + i)->id = i*i;
    }

    if(!PersonListIsEmpty(list) )                             /*  Check is empty      */
    { return 1;  }

    IF_FAIL(PersonListCount(list) )

    if(PersonListCount(list) )                                /*  Check list count    */
    {  return 1;  }

    for(i = (sizeof(pArr)/sizeof(Person)); i > 0; --i)   /*  Push to head 7..1   */
    {
        PersonListPushH(list, pArr + i-1);
    }

    if(sizeof(pArr)/sizeof(Person) != PersonListCount(list))
    {  return 1;  }

    data1 = PersonListHead(list);
    if(data1->age != pArr[0].age)                             /*  Check head  */
    {  return 1;  }

    data2 = PersonListTail(list);
    if(data2->age != pArr[sizeof(pArr)/sizeof(Person) -1].age) /*  Check tail  */
    {  return 1;  }

    for(i = 0; i < (sizeof(pArr2)/sizeof(Person)); ++i)  /*  Now pushing to tail 8 9 10  */
    {
        PersonListPushT(list, pArr2 + i);
    }

    if(sizeof(pArr)/sizeof(Person) + sizeof(pArr2)/sizeof(Person) != PersonListCount(list))
    {  return 1;  }

    numOfE = PersonListCount(list);

    for(i = 0; i < numOfE; ++i)             /*  Pop from head and accept to get fom 1..10   */
    {
        data1 = PersonListHead(list);
        printf("%d\n", data1->age);
        if(data1->age != i)
        {  return 1;  }
        PersonListPopH(list);
    }
    PersonListDel(list);

    return 0;
}


int ListPop_Utest()
{
    List*   list = ListNew()            ;
    int     numArr[] = {1,2,3,4,5,6,7}  ;
    int     numArr2[] = {8,9,10}        ;
    int*    data                        ;
    int     i                           ;
    int     numOfE                      ;

    if(!ListIsEmpty(list) )
    {  return 1;  }

    printf("The arguments pushed to list: ");
    for(i = (sizeof(numArr)/sizeof(int)); i > 0; --i)
    {
        ListPushH(list, numArr + i-1);
        printf("%d ",*(numArr + i - 1));
    }
    printf("\nThe args pushed to list are: %d 'in list: %d\n",sizeof(numArr)/sizeof(int), ListCount(list));
    printf("Now pushing to tail: ");

    for(i = 0; i < (sizeof(numArr2)/sizeof(int)); ++i)
    {
        ListPushT(list, numArr2 + i);
        printf("%d ",*(numArr2 + i));
    }

    printf("\nThe args in list: %d\n", ListCount(list));
    numOfE = ListCount(list);
    printf("Now pop from tail and prints the tail after popping\n");

    for(i = 0; i < numOfE; ++i)
    {
        data = ListTail(list);
        printf("The element is: %d\n", *data);
        ListPopT(list);
    }

    return 0;
}

int ListFindIf_Utest()
{
    PersonList* list = PersonListNew();
    Person pArr[5];
    Person* pp = pArr;
    int i;
    int age = 3;

    for(i = 0; pp < pArr + sizeof(pArr)/sizeof(Person); ++pp, ++i)
    {
        pp->age = i;
        pp->id = i*i;
    }
    printf("Insert array of Perons to list\n");
    PersonListPushTM(list, sizeof(pArr)/sizeof(Person), pArr);
    printf("The list count is: %d\n", PersonListCount(list));
    pp = PersonListFindIf(list, IsPersonMatch, &age);
    printf("The searched age was: %d, the person found age: %d, id: %d\n", age, pp->age, pp->id);
    if(age != pp->age)
    {  return 1;  }
    age = 10;               /*  Not in List */
    pp = PersonListFindIf(list, IsPersonMatch, &age);
    if(pp)
    {  return 1;  }



    return 0;
}

int ListMultipile_Utest()
{
    PersonList*   list = PersonListNew();
    Person  pArr[5]         ;
    Person* pp = pArr       ;
    int     i               ;
    int     numOfeE         ;
    int     popSizeH = 1    ;
    int     popSizeT = 3    ;

    printf("The ages inserted all of them in order head and by order from tail\n");
    for(i = 0; pp < pArr + sizeof(pArr)/sizeof(Person); ++pp, ++i)
    {
        pp->age = i;
        printf("%d ", i);
        pp->id = i*i;
    }
    PersonListPushTM(list, sizeof(pArr)/sizeof(Person), pArr);
    PersonListPushHM(list, sizeof(pArr)/sizeof(Person), pArr);

    printf("\nThe list count is: %d\n", PersonListCount(list));
    if(PersonListCount(list) != 2*sizeof(pArr)/sizeof(Person) )       /*  Check the correctnce of list size   */
    {  return 1;  }
    PersonListPopHM(list, popSizeH);
    printf("The list count after removed %d items from head is: %d\n", popSizeH,PersonListCount(list));
    if(PersonListCount(list) != 2*sizeof(pArr)/sizeof(Person) - popSizeH )
    {  return 1;  }
    PersonListPopTM(list, popSizeT);
    printf("The list count after removed %d items from tail is: %d\n", popSizeT,PersonListCount(list));
    if(PersonListCount(list) != 2*sizeof(pArr)/sizeof(Person) - popSizeH -popSizeT)
    {  return 1;  }
    printf("The ages after %d popped from head, and %d from tail\n",popSizeH, popSizeT);
    numOfeE = PersonListCount(list);
    for(i = 0; i < numOfeE ; ++i)
    {
        pp = PersonListHead(list);
        printf("%d ", pp->age);
        PersonListPopH(list);
    }
    puts("\n");
    PersonListDel(list);

    return 0;
}



int main()
{
    ElephantList* eList = ElephantListNew();
    Elephant e1 = {30, 100, "bobby"};
    Elephant e2 = {5, 60, "yoav"};
    Elephant* etest;
    /*Person* ptest;
    Person p1 = {23, 55, 77,"popo"};*/

    ElephantListPushH(eList, &e1);
    ElephantListPushH(eList, &e2);

    etest = ElephantListHead(eList);
    printf("%d \n",ElephantListCount(eList));

    printf("%s\n",etest->name);

    ListRegression_Utest();
    return 0;
}
